

;底层汇编文件
;线程切换汇编代码
;移植时需要处理, 根据平台修改
;将此文件的PendSV_Handler设置为PendSV中断调用
;适用于CortexM4F M7


  AREA |.text|,CODE,READONLY
  THUMB
  PRESERVE8


  ;对外提供的接口
  GLOBAL PendSV_Handler                                           ;软件中断, 其优先级必须设置为最低
  GLOBAL H_TS_LL_StartFirstThread                                 ;提供给C环境, 用于H_TS_LL_ThreadScheduleISR的初始化

  ;引入声明
  EXTERN H_TS_LL_ThreadScheduleISR                                ;调度中断调用, 软件中断将执行其指向的代码
  EXTERN H_TS_LL_Core_Instance                                    ;指向当前运行的线程句柄, 它仅可能被H_TS_LL_CurrentThreadRefresh更新
  EXTERN H_TS_LL_CurrentThreadRefresh                             ;其指向的代码进行当前线程的切换(更新H_TS_LL_Core_Instance)


H_TS_LL_ThreadSwitch PROC
  LDR       R1,=H_TS_LL_Core_Instance                             ;加载指向当前线程句柄的指针的地址
  LDR       R1,[R1]                                               ;加载当前线程的栈指针的地址(当前线程句柄的指针)

  PUSH      {R1,LR}                                               ;需要注意使栈8字节对齐(C环境的需求)
  BL        H_TS_LL_CurrentThreadRefresh                          ;更新当前线程信息 其返回更新后的线程句柄
  ;LDR       R0,=H_TS_LL_CurrentThreadRefresh
  ;BLX       R0
  POP       {R1,LR}

  CMP       R0,R1                                                 ;线程是否切换
  IT        EQ
  BXEQ      LR                                                    ;如果相等 没有发生线程切换 直接返回


  ;开始保存旧线程的状态
  MRS       R2,PSP                                                ;读线程栈指针

  ;判断线程是否使用了FPU 如果使用了 保存浮点寄存器
  TST       LR,#0x00000010
  IT        EQ
  VSTMDBEQ  R2!,{S16-S31}

  STMDB     R2!,{R4-R11,LR}                                       ;保存现场
  STR       R2,[R1]                                               ;保存栈指针到旧线程的句柄


  ;开始恢复新线程的状态
  LDR       R2,[R0]                                               ;读取栈指针
  LDMIA     R2!,{R4-R11,LR}                                       ;恢复现场

  ;判断线程是否使用了FPU 如果使用了 恢复浮点寄存器
  TST       LR,#0x00000010
  IT        EQ
  VLDMIAEQ  R2!,{S16-S31}

  MSR       PSP,R2                                                ;恢复堆栈指针


  BX        LR                                                    ;状态已经恢复为新线程的状态, 直接返回
  ENDP

;启动第一个线程
H_TS_LL_StartFirstThread PROC
  LDR       R0,=H_TS_LL_ThreadScheduleISR
  LDR       R1,=H_TS_LL_ThreadSwitch
  STR       R1,[R0]


  DSB
  ISB
  CPSID     I                                                     ;对主堆栈进行设置时须关闭中断
  DSB
  ISB

  LDR       R0,=0xE000ED00                                        ;SCB基地址
  LDR       R0,[R0,#8]                                            ;VTOR
  LDR       R0,[R0]                                               ;初始MSP
  MSR       MSP,R0                                                ;MSP恢复初始值, 最大化中断可用堆栈

  MOV       R0,#0
  MSR       CONTROL,R0                                            ;设置CONTROL 设置为特权级,使用MSP (主要是为了清除FPCA)

  DSB
  ISB
  CPSIE     I                                                     ;开启中断
  DSB
  ISB


  LDR       R1,=H_TS_LL_Core_Instance                             ;加载指向当前线程句柄的指针的地址
  LDR       R1,[R1]                                               ;加载当前线程的栈指针的地址(当前线程句柄的指针)
  LDR       R2,[R1]                                               ;读取栈指针

  LDMIA     R2!,{R4-R11,LR}                                       ;恢复现场
  MSR       PSP,R2                                                ;恢复堆栈指针


  BX        LR                                                    ;状态已经恢复为新线程的状态, 直接返回
  ENDP

;需要将下面的方法设为PendSV中断调用
PendSV_Handler PROC
  LDR       R0,=H_TS_LL_ThreadScheduleISR
  LDR       R0,[R0]
  BX        R0
  ENDP


  ALIGN     4

  END



